package org.wdcode.core.lucene.search;

import java.util.List;
import java.util.Map;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.TopDocs;
import org.wdcode.common.exception.CustomRuntimeException;
import org.wdcode.common.tools.Lists;
import org.wdcode.common.tools.Maps;
import org.wdcode.common.util.CommonUtil;
import org.wdcode.core.lucene.index.LuceneIndex;
import org.wdcode.core.lucene.need.LuceneNeed;

/**
 * LuceneSearch的实现类
 * @author WD
 * @since JDK6
 * @version 1.0 2010-07-15
 */
final class LuceneSearchImpl implements LuceneSearch {
	// LuceneIndex
	private LuceneIndex					index;
	// 查询器
	private Searcher					searcher;
	// LuceneNeed
	private LuceneNeed					need;
	// QueryParser集合
	private Map<String, QueryParser>	queryParsers;

	/**
	 * 私有构造
	 * @param index LuceneIndex
	 */
	public LuceneSearchImpl(LuceneIndex index) {
		this.index = index;
		this.need = index.getLuceneNeed();
		this.searcher = need.getSearcher();
		this.queryParsers = Maps.getConcurrenrMap();
	}

	/**
	 * 获得LuceneIndex
	 * @return LuceneIndex
	 */
	public final LuceneIndex getLuceneIndex() {
		return index;
	}

	/**
	 * 查询获得值
	 * @param field 要查询的字段
	 * @param query 查询词
	 * @return 获得值的Map
	 */
	public final Map<String, String> query(String field, String query) {
		return getFieldable(getDocument(getQueryParser(field), query, 1)).get(0);
	}

	/**
	 * 查询获得值
	 * @param field 要查询的字段
	 * @param query 查询词
	 * @param num 数量
	 * @return 获得值的列表
	 */
	public final List<Map<String, String>> query(String field, String query, int num) {
		return getFieldable(getDocument(getQueryParser(field), query, num));
	}

	/**
	 * 查询获得文档列表
	 * @param query
	 * @return
	 */
	private List<Document> getDocument(QueryParser parser, String query, int num) {
		// 声明一个空列表
		List<Document> list = Lists.emptyList();
		try {
			// 获得Query
			Query q = parser.parse(query);
			// 获得TopDocs
			TopDocs topDocs = searcher.search(q, num);
			// 获得ScoreDoc数组
			ScoreDoc[] scoreDocs = topDocs.scoreDocs;
			// 获得数组长度
			int length = scoreDocs.length;
			// 获得列表
			list = Lists.getList(length);
			// 循环ScoreDoc数组
			for (int i = 0; i < scoreDocs.length; i++) {
				// 添加到List中
				list.add(searcher.doc(scoreDocs[i].doc));
			}
		} catch (Exception e) {
			throw new CustomRuntimeException(e);
		}
		// 返回列表
		return list;
	}

	/**
	 * 根据文档列表 获得字段Map列表
	 * @param lsDocument 文档列表
	 * @return 字段Map列表
	 */
	private List<Map<String, String>> getFieldable(List<Document> lsDocument) {
		// 文档列表大小
		int size = lsDocument.size();
		// 声明列表
		List<Map<String, String>> list = Lists.getList(size);
		// 循环ScoreDoc数组
		for (int i = 0; i < lsDocument.size(); i++) {
			// 添加到List中
			list.add(getFieldable(lsDocument.get(i)));
		}
		// 返回列表
		return list;
	}

	/**
	 * 获得文档里的所有字段 转换成Map
	 * @param doc 文档
	 * @return 转换后的Map
	 */
	private Map<String, String> getFieldable(Document doc) {
		// 获得字段列表
		List<Fieldable> lsField = doc.getFields();
		// 获得字段列表大小
		int size = lsField.size();
		// 声明Map
		Map<String, String> map = Maps.getMap(size);
		// 循环字段列表
		for (int i = 0; i < size; i++) {
			// 获得字段
			Fieldable f = lsField.get(i);
			// 添加到Map中
			map.put(f.name(), f.stringValue());
		}
		// 返回Map
		return map;
	}

	/**
	 * 获得QueryParser
	 * @param field 字段名
	 * @return QueryParser
	 */
	private QueryParser getQueryParser(String field) {
		// 获得QueryParser
		QueryParser parser = queryParsers.get(field);
		// 判断QueryParser是否为空
		if (CommonUtil.isEmpty(parser)) {
			// 实例化 QueryParser
			parser = new QueryParser(need.getVersion(), field, need.getAnalyzer());
			// 添加到map中
			queryParsers.put(field, parser);
		}
		// 返回QueryParser
		return parser;
	}
}
